package com.lifang.framework.util;

import com.lifang.framework.beans.factory.support.BeanDefinition;
import com.lifang.framework.beans.BeansException;

import java.lang.reflect.Constructor;

/**
 * 构造器工具类
 */
public class ConstructorUtil {

    public static Constructor<?> findFitConstructor(BeanDefinition definition, Object[] args) {
        try {
            Class<?> beanClass = definition.getBeanClass();
            if (args.length == 0 && !definition.hasConstructorArgument()) {
                return beanClass.getDeclaredConstructor();
            }
            Constructor<?> constructorUsed = null;
            if (args.length > 0) {
                outer:
                for (Constructor<?> constructor : beanClass.getDeclaredConstructors()) {
                    if (constructor.getParameterCount() == args.length) {
                        Class<?>[] parameterTypes = constructor.getParameterTypes();
                        for (int i = 0; i < parameterTypes.length; i++) {
                            Object arg = args[i];
                            Class<?> parameterType = parameterTypes[i];
                            if (arg == null || !parameterType.isAssignableFrom(arg.getClass())) {
                                continue outer;
                            }
                        }
                        constructorUsed = constructor;
                        break;
                    }
                }
            } else if (definition.hasConstructorArgument()) {
                outer:
                for (Constructor<?> constructor : beanClass.getDeclaredConstructors()) {
                    if (definition.getConstructorSize() == constructor.getParameterCount()) {
                        Class<?>[] parameterTypes = constructor.getParameterTypes();
                        for (int i = 0; i < parameterTypes.length; i++) {
                            Class<?> parameterType = parameterTypes[i];
                            Object constructorValue = definition.getConstructorValue(i, parameterType);
                            if (constructorValue == null || !constructorValue.getClass().isAssignableFrom(parameterType)) {
                                continue outer;
                            }
                        }
                        constructorUsed = constructor;
                        break;
                    }
                }
            }
            if (constructorUsed == null) {
                throw new NoSuchMethodException();
            }
            return constructorUsed;
        } catch (NoSuchMethodException exception) {
            throw new BeansException(definition.getBeanClass().getName() + " has Nothing suitable Constructor Used to initialize");
        }
    }
}
